#include "Precompile.h"
#include "DX11RenderTarget.h"
#include "DX11Texture2D.h"
#include "DX11RenderSystem.h"

namespace Graphics{
	DX11RenderTarget::DX11RenderTarget(Texture2DPtr texture, RenderContext *handle):RenderTarget(texture,handle),m_renderTarget(NULL),m_depthStencilTexture(NULL),m_depthStencil(NULL){
		DX11Texture2DPtr tex = boost::static_pointer_cast<DX11Texture2D>(texture);

		// Create render target view
		D3D11_RENDER_TARGET_VIEW_DESC rtDesc;
		rtDesc.Format = tex->getFormat();
		if(tex->m_multisample > 1)
			rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
		else
			rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
		rtDesc.Texture2D.MipSlice = 0;

		HRESULT hr = handle->m_handle->CreateRenderTargetView( tex->getTexture(), &rtDesc, &m_renderTarget );
		if(FAILED(hr)){
			LOG_ERROR("Unable to create render target from texture");
			assert(0);
		}

		// Create depth stencil texture.
		D3D11_TEXTURE2D_DESC desc;
		ZeroMemory( &desc, sizeof(desc) );
		desc.Width = tex->m_width;
		desc.Height = tex->m_height;
		desc.MipLevels = 1;
		desc.Format = DXGI_FORMAT_D32_FLOAT;
		desc.SampleDesc.Count = tex->m_multisample;
		if(tex->m_multisample > 1)
			desc.SampleDesc.Quality = tex->m_qualityLevels-1;
		else
			desc.SampleDesc.Quality = 0;
		desc.Usage = D3D11_USAGE_DEFAULT;
		desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
		desc.CPUAccessFlags = 0;
		desc.MiscFlags = 0;
		desc.ArraySize = 1;
		if(FAILED(handle->m_handle->CreateTexture2D(&desc, NULL, &m_depthStencilTexture))){
			LOG_ERROR("Failed to create depth stencil texture.");
			assert(0);
		}

		D3D11_DEPTH_STENCIL_VIEW_DESC DescDS;
		DescDS.Format = DXGI_FORMAT_D32_FLOAT;
		if(tex->m_multisample > 1)
			DescDS.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
		else
			DescDS.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
		DescDS.Texture2D.MipSlice = 0;
		DescDS.Flags = 0;
		if(FAILED(handle->m_handle->CreateDepthStencilView(m_depthStencilTexture, &DescDS, &m_depthStencil))){
			// Error handling
			LOG_ERROR("DX11RenderSystem::resetRenderSystem - Failed to create depth stencil view.");
			assert(0);
		}
	}

	DX11RenderTarget::~DX11RenderTarget(){
		if(m_renderTarget)
			m_renderTarget->Release();
		if(m_depthStencilTexture)
			m_depthStencilTexture->Release();
		if(m_depthStencil)
			m_depthStencil->Release();
	}

	void DX11RenderTarget::clear(bool clearRT, bool clearDS, RenderContext *handle){
		DX11RenderContext* context = (DX11RenderContext*)handle;
		if(clearDS)
			context->m_context->ClearDepthStencilView(m_depthStencil, D3D11_CLEAR_DEPTH, 1.0, 0);
		if(clearRT){
			FLOAT black[] = {0,0,0,0};
			context->m_context->ClearRenderTargetView(m_renderTarget, black);
		}
	}

	void DX11RenderTarget::setRenderTarget(bool clearRT, bool clearDS, RenderContext *handle){
		DX11RenderContext* context = (DX11RenderContext*)handle;

		clear(clearRT,clearDS,handle);
		context->m_context->OMSetRenderTargets(1,&m_renderTarget,m_depthStencil);
	}

	void DX11RenderTarget::resolveIntoTexture(Texture2DPtr texture, RenderContext *handle){
		DX11RenderContext* context = (DX11RenderContext*)handle;
		boost::shared_ptr<DX11Texture2D> tex = boost::static_pointer_cast<DX11Texture2D>(texture);

		context->m_context->ResolveSubresource(tex->getTexture(), D3D11CalcSubresource(0, 0, 1), boost::static_pointer_cast<DX11Texture2D>(m_texture)->getTexture(), D3D11CalcSubresource(0, 0, 1), tex->getFormat());
	}

	void DX11RenderTarget::resolveIntoRenderTarget(RenderTargetPtr renderTarget, RenderContext *handle){
		resolveIntoTexture(renderTarget->getTexture(),handle);
	}
}